package apps.sim.http;

import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import apps.sim.action.handler.HandlerFactory;
import apps.sim.core.IHandler;
import apps.sim.core.IHandler.IHandlerConfig;
import apps.sim.util.Callback;

import com.sun.net.httpserver.Headers;
import com.sun.net.httpserver.HttpExchange;

public class HttpClassLookupHandler extends HttpBaseHandler {
	public static Callback<URL> bundleSrcCallback;

	public void execute(HttpExchange exchange) throws Exception {
		final List<String> handlers = new ArrayList<String>();
		final Set<String> clazzez = getClassNamesFromPackage();
		for (String string : clazzez) {
			try {
				final Class<?> clazz = HandlerFactory.getInstance().getClass(string);

				if (!Modifier.isAbstract(clazz.getModifiers()) && !clazz.isInterface() && (IHandler.class.isAssignableFrom(clazz))) {
					handlers.add(string);
				}
			} catch (ClassNotFoundException e) {
				// eat e.printStackTrace();
			}
		}
		final Headers responseHeaders = exchange.getResponseHeaders();
		responseHeaders.set("Content-Type", "text/html;charset=utf-8");
		exchange.sendResponseHeaders(200, 0);
		final OutputStream responseBody = exchange.getResponseBody();
		final Map<String, String> params = extractParams(exchange.getRequestURI());
		Collections.sort(handlers);
		for (String string : handlers) {
			final IHandler handler = HandlerFactory.getInstance().getHandler(string);
			if (handler != null) {
				String description = handler.getDescription();
				final IHandlerConfig configuration = handler.getHandlerConfiguration();
				final boolean isConfig = configuration != null ? true : false;
				final String string2 = "<a href=\"javascript:addValue(" + params.get("rowid") + ",'" + string + "', '" + isConfig + "')\" alt=\""
						+ description + "\" title=\"" + description + "\">" + string + "</a>";
				responseBody.write(string2.getBytes());
				responseBody.write("<br/>".getBytes());
			}
		}
		responseBody.close();
	}

	private Set<String> getClassNamesFromPackage() throws IOException {
		Set<String> names = new HashSet<String>();
		for (String packageName : HandlerFactory.getInstance().PACKAGES) {
			final String packaze = packageName;
			final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
			URL packageURL;
			packageName = packageName.replace(".", "/");
			packageURL = classLoader.getResource(packageName);
			if (packageURL.getProtocol().equals("jar")) {
				String jarFileName = URLDecoder.decode(packageURL.getFile(), "UTF-8");
				jarFileName = jarFileName.substring(5, jarFileName.indexOf("!"));
				final JarFile jf = new JarFile(jarFileName);
				final Enumeration<JarEntry> jarEntries = jf.entries();
				while (jarEntries.hasMoreElements()) {
					final JarEntry nextElement = jarEntries.nextElement();
					if (!nextElement.isDirectory()) {
						String entryName = nextElement.getName();
						if (entryName.startsWith(packageName) && entryName.length() > packageName.length() + 5) {
							entryName = entryName.substring(packageName.length() + 1, entryName.lastIndexOf('.'));
							names.add(packaze + "." + entryName.replaceAll("/", "."));
						}
					}
				}
				jf.close();
			} else if (packageURL.getProtocol().equals("bundleresource")) {
				if (bundleSrcCallback != null) {
					final URL fileName = bundleSrcCallback.call(packageURL);
					File folder = new File(fileName.getFile());
					files(names, folder, packaze);
				}
			} else {
				File folder = new File(packageURL.getFile());
				files(names, folder, packaze);
			}

		}
		names.addAll(HandlerFactory.getInstance().CLASSE_NAMES);
		return names;
	}

	private void files(Set<String> names, File folder, String packaze) {
		final File[] contenuti = folder.listFiles();
		String entryName;
		for (File actual : contenuti) {
			if (actual.isDirectory()) {
				files(names, actual, packaze + "." + actual.getName());
			} else {
				entryName = actual.getName();
				if (entryName.endsWith(".class")) {
					entryName = entryName.substring(0, entryName.lastIndexOf('.'));
					names.add(packaze + "." + entryName);
				}
			}
		}
	}

}
